package com.cmy.framework_base.channel

import androidx.lifecycle.Lifecycle
import androidx.lifecycle.LifecycleOwner
import androidx.lifecycle.MutableLiveData
import kotlinx.coroutines.CoroutineScope
import kotlinx.coroutines.Job
import kotlinx.coroutines.ObsoleteCoroutinesApi
import kotlinx.coroutines.channels.BroadcastChannel
import kotlinx.coroutines.launch

/**
 * @name:
 *  channel
 * @package:
 *  com.cmy.framework_base.channel
 * @date:
 *  2023/2/2711:55
 * @author
 *    cmy
 * @description
 *
 */


@OptIn(ObsoleteCoroutinesApi::class)
@PublishedApi
internal var broadcastChannel = BroadcastChannel<ChannelEvent<Any>>(102400)


/**
 * 发送事件
 * @param event 事件
 * @param tag 标签, 使用默认值空, 则接受者将忽略标签, 仅匹配事件
 */
@OptIn(ObsoleteCoroutinesApi::class)
fun sendEvent(tag: String? = null,event: Any ) = ChannelScope().launch {
    broadcastChannel.send(ChannelEvent(event, tag))
}


/**
 * 发送标签
 * @param tag 标签
 */
@OptIn(ObsoleteCoroutinesApi::class)
fun sendTag(tag: String?) = ChannelScope().launch {
    broadcastChannel.send(ChannelEvent(ChannelTag(), tag))
}



/**
 * 接收事件
 *
 * @param tags 可接受零个或多个标签, 如果标签为零个则匹配事件对象即可成功接收, 如果为多个则要求至少匹配一个标签才能成功接收到事件
 * @param block 接收到事件后执行函数,以及对应的标签
 */
@OptIn(ObsoleteCoroutinesApi::class)
inline fun <reified T> LifecycleOwner.receiveEvent(
    vararg tags: String? = emptyArray(),
    lifeEvent: Lifecycle.Event = Lifecycle.Event.ON_DESTROY,
    noinline block: suspend CoroutineScope.(event: T,tag:String?) -> Unit
): Job {
    val coroutineScope = ChannelScope(this, lifeEvent)
    return coroutineScope.launch {
        for (bus in broadcastChannel.openSubscription()) {
            if (bus.event is T && (tags.isEmpty() || tags.contains(bus.tag))) {
                block(bus.event,bus.tag)
            }
        }
    }
}




/**
 * 使用LiveData将消息延迟到前台接收
 */
@OptIn(ObsoleteCoroutinesApi::class)
inline fun <reified T> LifecycleOwner.receiveEventLive(
    vararg tags: String? = arrayOf(),
    lifeEvent: Lifecycle.Event = Lifecycle.Event.ON_DESTROY,
    noinline block: suspend CoroutineScope.(event: T,tag:String?) -> Unit
): Job {
    val coroutineScope = ChannelScope(this, lifeEvent)
    return coroutineScope.launch {
        for (bus in broadcastChannel.openSubscription()) {
            if (bus.event is T && (tags.isEmpty() || tags.contains(bus.tag))) {
                val liveData = MutableLiveData<T>()
                liveData.observe(this@receiveEventLive) { coroutineScope.launch { block(it,bus.tag) } }
                bus.event.let {
                    liveData.value = it
                }
            }
        }
    }
}




/**
 * 接收事件, 此事件要求执行[kotlinx.coroutines.cancel]手动注销
 *
 * @param tags 可接受零个或多个标签, 如果标签为零个则匹配事件对象即可成功接收, 如果为多个则要求至少匹配一个标签才能成功接收到事件
 * @param block 接收到事件后执行函数,以及数据标签，支持通过标签反向对比数据
 */
@OptIn(ObsoleteCoroutinesApi::class)
inline fun <reified T> receiveEventHandler(
    vararg tags: String? = arrayOf(),
    noinline block: suspend CoroutineScope.(event: T,tag:String?) -> Unit
): Job {
    val coroutineScope = ChannelScope()
    return coroutineScope.launch {
        for (bus in broadcastChannel.openSubscription()) {
            if (bus.event is T && (tags.isEmpty() || tags.contains(bus.tag))) {
                block(bus.event,bus.tag)
            }
        }
    }
}


/**
 * 接收标签, 和[receiveEvent]不同之处在于该函数仅支持标签, 不支持事件+标签
 *
 * @param tags 可接受零个或多个标签, 如果标签为零个则匹配事件对象即可成功接收, 如果为多个则要求至少匹配一个标签才能成功接收到事件
 * @param block 接收到事件后执行函数
 */
@OptIn(ObsoleteCoroutinesApi::class)
fun LifecycleOwner.receiveTag(
    vararg tags: String?,
    lifeEvent: Lifecycle.Event = Lifecycle.Event.ON_DESTROY,
    block: suspend CoroutineScope.(tag:String) -> Unit
): Job {
    val coroutineScope = ChannelScope(this, lifeEvent)
    return coroutineScope.launch {
        for (bus in broadcastChannel.openSubscription()) {
            if (bus.event is ChannelTag && !bus.tag.isNullOrBlank() && tags.contains(bus.tag)) {
                block(bus.tag)
            }
        }
    }
}


/**
 * 使用LiveData将消息延迟到前台接收,只接收标签
 */
@OptIn(ObsoleteCoroutinesApi::class)
fun LifecycleOwner.receiveTagLive(
    vararg tags: String?,
    lifeEvent: Lifecycle.Event = Lifecycle.Event.ON_DESTROY,
    block: suspend CoroutineScope.(tag: String) -> Unit
): Job {
    val coroutineScope = ChannelScope(this, lifeEvent)
    return coroutineScope.launch {
        for (bus in broadcastChannel.openSubscription()) {
            if (bus.event is ChannelTag && !bus.tag.isNullOrBlank() && tags.contains(bus.tag)) {
                val liveData = MutableLiveData<String>()
                liveData.observe(this@receiveTagLive) { coroutineScope.launch { block(it) } }
                bus.tag.let {
                    liveData.value = it
                }
            }
        }
    }
}


/**
 * 接收标签, 和[receiveEvent]不同之处在于该函数仅支持标签, 不支持事件+标签, 此事件要求执行[kotlinx.coroutines.cancel]手动注销
 *
 * @param tags 可接受零个或多个标签, 如果标签为零个则匹配事件对象即可成功接收, 如果为多个则要求至少匹配一个标签才能成功接收到事件
 * @param block 接收到事件后执行函数
 */
@OptIn(ObsoleteCoroutinesApi::class)
fun receiveTagHandler(
    vararg tags: String?,
    block: suspend CoroutineScope.(tag: String) -> Unit
): Job {
    val coroutineScope = ChannelScope()
    return coroutineScope.launch {
        for (bus in broadcastChannel.openSubscription()) {
            if (bus.event is ChannelTag && !bus.tag.isNullOrEmpty() && tags.contains(bus.tag)) {
                block(bus.tag)
            }
        }
    }
}